﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Control_Layer;

namespace Mindmap_Case_4
{
    public partial class Main : Form
    {
        /// <summary>
        /// Enumerator for the Lastselected component.
        /// </summary>
        private enum LastSelected
        {
            Body,
            Relation,
            Picture,
            Select,
            Move
        }

        /// <summary>
        /// Enumerator for the lastselected Edit style.
        /// </summary>
        private enum Edit
        {
            None,
            Color,
            Text,
            Delete
        }

        private LastSelected lastSelected;
        private Edit edit;

        public Main()
        {
            InitializeComponent();

            pnlColor.BackColor = cdPickColor.Color;
            msiAbout.Text = "About " + this.Text;

            updateMindmapList();
            lastSelected = LastSelected.Select;
        }

        private int sx, sy;
        private int ex, ey;

        private bool selectionMade;

        private Bitmap screen;

        /// <summary>
        /// If the user clicks on help in the color palette.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void cdPickColor_HelpRequest(object sender, EventArgs e)
        {
            MessageBox.Show("Do you really need help picking a color?", 
                            "Seriously?", 
                            MessageBoxButtons.OK, 
                            MessageBoxIcon.Question);
        }

        /// <summary>
        /// Opens the color dialog.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnPickColor_Click(object sender, EventArgs e)
        {
            CCSelectColor ccSelectColor = new CCSelectColor();
            if (cdPickColor.ShowDialog() == DialogResult.OK)
            {
                pnlColor.BackColor = cdPickColor.Color;
                ccSelectColor.SetColor(cdPickColor.Color);
            }

            if (lastSelected == LastSelected.Select &&
                selectionMade)
            {
                edit = Edit.Color;
                editComponent();
            }
        }

        /// <summary>
        /// Edits the text of the selected item.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnEditText_Click(object sender, EventArgs e)
        {
            if (lastSelected == LastSelected.Select &&
                selectionMade)
            {
                edit = Edit.Text;
                editComponent();
            }
        }

        /// <summary>
        /// Deletes the selected item.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnDeleteComponent_Click(object sender, EventArgs e)
        {
            if (lastSelected == LastSelected.Select &&
                selectionMade)
            {
                edit = Edit.Delete;
                editComponent();
            }
        }

        /// <summary>
        /// Exits the application.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void msiExit_Click(object sender, EventArgs e)
        {
            Application.Exit();
        }

        /// <summary>
        /// Button to start adding a body.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnAddBody_Click(object sender, EventArgs e)
        {
            lastSelected = LastSelected.Body;
            this.MouseDown += Main_MouseDown;
        }

        /// <summary>
        /// Button to start adding a relation.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnAddRelation_Click(object sender, EventArgs e)
        {
            lastSelected = LastSelected.Relation;
            this.MouseDown += Main_MouseDown;
        }

        /// <summary>
        /// Adds a submindmap to the current project.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void msiAddMindmap_Click(object sender, EventArgs e)
        {
            CCAddSubmindmap ccAddSubmindmap = new CCAddSubmindmap();
            InputBox inputBox = new InputBox();
            if (inputBox.ShowDialog() == DialogResult.OK)
            {
                ccAddSubmindmap.Add(inputBox.GetText);
            }

            updateMindmapList();
        }

        /// <summary>
        /// Adds a submindmap to the current project.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnAddMindmap_Click(object sender, EventArgs e)
        {
            CCAddSubmindmap ccAddSubmindmap = new CCAddSubmindmap();
            InputBox inputBox = new InputBox();
            if (inputBox.ShowDialog() == DialogResult.OK)
            {
                ccAddSubmindmap.Add(inputBox.GetText);
            }

            updateMindmapList();
        }

        /// <summary>
        /// Triggers a step to be undone.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void msiUndo_Click(object sender, EventArgs e)
        {
            CCUndoStep ccUndoStep = new CCUndoStep();
            ccUndoStep.UndoStep();
            updateMindmap();
        }

        /// <summary>
        /// Triggers a step to be redone.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void msiRedo_Click(object sender, EventArgs e)
        {
            CCRedoStep ccRedoStep = new CCRedoStep();
            ccRedoStep.RedoStep();
            updateMindmap();
        }

        /// <summary>
        /// Starts the PreviewPresentation dialog.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void msiPreviewPresentation_Click(object sender, EventArgs e)
        {
            PreviewPresentation previewPresentation = new PreviewPresentation();
            previewPresentation.ShowDialog();
        }

        /// <summary>
        /// Opens a saveFileDialog. Saves the project.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void msiSave_Click(object sender, EventArgs e)
        {
            CCSaveFile ccSaveFile = new CCSaveFile();
            sfdMain.ShowDialog();
            sfdMain.Filter = "Over Ninethousand File|*.ont";

            if (sfdMain.FileName != null)
            {
                ccSaveFile.SaveFile(sfdMain.FileName);
            }
        }

        /// <summary>
        /// Save a project as HTML.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void msiSaveAsHtml_Click(object sender, EventArgs e)
        {
            CCSaveAsHtmlFile ccSaveAsHtmlFile = new CCSaveAsHtmlFile();
            
            try
            {
                if (fbdMain.ShowDialog() == DialogResult.OK) 
                    ccSaveAsHtmlFile.Save(fbdMain.SelectedPath + @"\", Properties.Resources.template);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.StackTrace);
                Console.WriteLine("Crashed whilst loading HTML template.");
            }
        }

        /// <summary>
        /// Opens an openFileDialog. Opens a new project.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void msiOpen_Click(object sender, EventArgs e)
        {
            CCOpenFile ccOpenFile = new CCOpenFile();
            ofdMain.Filter = "Over NineThousand File|*.ont";
            if (ofdMain.FileName != null && ofdMain.ShowDialog() == DialogResult.OK)
            {
                ccOpenFile.OpenFile(ofdMain.FileName);
                updateMindmapList();
                updateMindmap();
            }
        }

        /// <summary>
        /// Button to start adding a picture
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnPicture_Click(object sender, EventArgs e)
        {
            lastSelected = LastSelected.Picture;
            this.MouseDown += Main_MouseDown;
        }

        /// <summary>
        /// Button to start the presentation
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnPresentation_Click(object sender, EventArgs e)
        {
            Presentation presentationDialog = new Presentation();
            presentationDialog.Show();
        }

        /// <summary>
        /// Starts a selection for existing components.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Main_MouseDownSelect(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                if (lastSelected == LastSelected.Select) 
                    startComponentSelect(e);
            }
        }

        /// <summary>
        /// Starts a selection to add a component.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Main_MouseDown(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                this.MouseDown -= Main_MouseDown;
                if (lastSelected != LastSelected.Select)
                    startSelection(e);
            }
        }

        /// <summary>
        /// Keeps track of current mouse movements.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Main_MouseMove(object sender, MouseEventArgs e)
        {
            if (lastSelected != LastSelected.Select) 
                onSelection(e);
        }

        /// <summary>
        /// Ends the selection for adding new components.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Main_MouseUp(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                if (lastSelected == LastSelected.Select)
                    endComponentSelect(e);
                else 
                    endSelection(e);

                // Remove all mouse events
                this.MouseMove -= Main_MouseMove;
                this.MouseUp -= Main_MouseUp;
            }
        }

        /// <summary>
        /// Keeps track of the start of a selection.
        /// </summary>
        /// <param name="e"></param>
        private void startSelection(MouseEventArgs e)
        {
            if (e.X > 0 && e.X < 800 && e.Y > 24 && e.Y < 624)
            {
                sx = e.X;
                sy = e.Y - 24;

                this.MouseMove += Main_MouseMove;
                this.MouseUp += Main_MouseUp;

                if (lastSelected == LastSelected.Move)
                {
                    Service service = Service.GetInstance;
                    CCSelectComponent ccSelectComponent = service.GetCCSelectComponent;
                    ccSelectComponent.MakeSelection(sx, sy);
                    selectionMade = true;

                    updateStatusStrip();
                }
            }
        }

        /// <summary>
        /// Keeps track and previews components while triggered.
        /// </summary>
        /// <param name="e"></param>
        private void onSelection(MouseEventArgs e)
        {
            if (e.X > 0 && e.X < 800 && e.Y > 24 && e.Y < 624)
            {
                if (lastSelected == LastSelected.Body)
                {
                    CCPreviewComponent ccPreviewBody = new CCPreviewComponent();
                    drawMindmap(ccPreviewBody.PreviewBody(sx, sy, e.X, e.Y - 24));
                }
                else if (lastSelected == LastSelected.Relation)
                {
                    CCPreviewComponent ccPreviewBody = new CCPreviewComponent();
                    drawMindmap(ccPreviewBody.PreviewRelation(sx, sy, e.X, e.Y - 24));
                }
                else if (lastSelected == LastSelected.Picture)
                {
                    CCPreviewComponent ccPreviewBody = new CCPreviewComponent();
                    drawMindmap(ccPreviewBody.PreviewPicture(sx, sy, e.X, e.Y - 24));
                }
                else if (lastSelected == LastSelected.Move)
                {
                    CCEditSelected ccEditSelected = new CCEditSelected();
                    ccEditSelected.MoveComponent(e.X - sx, e.Y - 24 - sy);

                    sx = e.X;
                    sy = e.Y - 24;

                    updateMindmap();
                }
            }
        }

        /// <summary>
        /// Ends the selection and starts an action depending on LastSelected.
        /// </summary>
        /// <param name="e"></param>
        private void endSelection(MouseEventArgs e)
        {
            ex = e.X;
            ey = e.Y - 24; // -24 because of the offset caused by the menubar

            string name = null;

            if (lastSelected != LastSelected.Move)
            {
                InputBox input = new InputBox();
                input.ShowDialog();
                if (input.DialogResult == DialogResult.OK) // If entering name does not get cancelled, add the component
                {
                    name = input.GetText;

                    switch (lastSelected)
                    {
                        case LastSelected.Body:
                            CCAddBody ccAddBody = new CCAddBody();
                            screen = ccAddBody.Add(sx, sy, ex, ey, name);
                            break;
                        case LastSelected.Relation:
                            CCAddRelation ccAddRelation = new CCAddRelation();
                            ccAddRelation.Add(sx, sy, ex, ey, name);
                            break;
                        case LastSelected.Picture:
                            ofdMain.Filter = "Image Files (*.bmp, *. jpeg, *.jpg, *.png, *.gif)|*.bmp;*.jpeg;*.jpg;*.png; *.gif";
                            if (ofdMain.ShowDialog() == DialogResult.OK)
                            {
                                Bitmap picture = (Bitmap)Image.FromFile(ofdMain.FileName);
                                CCAddPicture ccAddPicture = new CCAddPicture();
                                ccAddPicture.Add(sx, sy, ex, ey, name, picture);
                            }
                            break;
                        default:
                            break;
                    }
                }
            }

            lastSelected = LastSelected.Select;
            updateMindmap();
        }

        /// <summary>
        /// Starts a selection for components.
        /// </summary>
        /// <param name="e"></param>
        private void startComponentSelect(MouseEventArgs e)
        {
            sx = e.X;
            sy = e.Y - 24;

            this.MouseDown -= Main_MouseDown;
            this.MouseUp += Main_MouseUp;
        }

        /// <summary>
        /// Ends a selection for components.
        /// </summary>
        /// <param name="e"></param>
        private void endComponentSelect(MouseEventArgs e)
        {
            Service service = Service.GetInstance;
            CCSelectComponent ccSelectComponent = service.GetCCSelectComponent;
            ccSelectComponent.MakeSelection(sx, sy);
            selectionMade = true;

            updateStatusStrip();

            this.MouseUp -= Main_MouseUp;
        }

        /// <summary>
        /// Updates the status strip's label.
        /// </summary>
        private void updateStatusStrip()
        {
            CCEditSelected ccEditSelected = new CCEditSelected();
            toolStripLabelSelected.Text = "Selected: " + ccEditSelected.GetText();                      
        }

        /// <summary>
        /// Starts editing a component depending on the Edit enumerator.
        /// </summary>
        private void editComponent()
        {
            CCEditSelected ccEditSelected = new CCEditSelected();
            switch (edit)
            {
                case Edit.Color:
                    ccEditSelected.EditColor(cdPickColor.Color);
                    edit = Edit.None;
                    selectionMade = false;
                    break;
                case Edit.Text:
                    InputBox input = new InputBox();
                    input.Text = "Edit";
                    input.SetPreviewText(ccEditSelected.GetText());
                    input.ShowDialog();

                    if (input.DialogResult == DialogResult.OK) 
                        ccEditSelected.EditText(input.GetText);

                    updateStatusStrip();
                    edit = Edit.None;
                    selectionMade = false;
                    break;
                case Edit.Delete:
                    ccEditSelected.DeleteComponent();
                    edit = Edit.None;
                    selectionMade = false;
                    break;
                default:
                    break;
            }
            updateMindmap();
        }

        /// <summary>
        /// Draw the mindmap to Forms screen.
        /// </summary>
        /// <param name="drawScreen"></param>
        private void drawMindmap(Bitmap drawScreen)
        {
            using (Graphics g = this.CreateGraphics())
            {
                g.DrawImage(drawScreen, new Point(0, 24));
            }
        }

        /// <summary>
        /// Update and repaint the mindmap.
        /// </summary>
        private void updateMindmap()
        {
            Service s = Service.GetInstance;
            screen = s.UpdateScreen();
            drawMindmap(screen);
        }

        /// <summary>
        /// Forms paint event.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Main_Paint(object sender, PaintEventArgs e)
        {
            if (screen == null)
            {
                screen = new Bitmap(800, 600);
                using (Graphics g = Graphics.FromImage(screen))
                {
                    g.Clear(Color.White);
                }
            }
            drawMindmap(screen);
        }

        /// <summary>
        /// Shows the About Dialog.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void msiAbout_Click(object sender, EventArgs e)
        {
            About about = new About();
            about.Show();
        }

        /// <summary>
        /// Updates the list with mindmaps (submindmaps).
        /// </summary>
        private void updateMindmapList()
        {
            CCSelectMindmap ccSelectMindmap = new CCSelectMindmap();

            try
            {
                int index = listExplorer.SelectedIndex;
                if (index < 0 || index > ccSelectMindmap.GetMindmaps().Count - 1)
                {
                    index = 0;
                }
                listExplorer.DataSource = ccSelectMindmap.GetMindmaps();
                listExplorer.SelectedIndex = index;
            }
            catch (ArgumentOutOfRangeException ex)
            {
                listExplorer.SelectedIndex = 0;
                Console.WriteLine(ex.Message);
            }
        }

        /// <summary>
        /// Changes the current selected mindmap to work in and to show on the screen.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void listExplorer_SelectedIndexChanged(object sender, EventArgs e)
        {
            CCSelectMindmap ccSelectMindmap = new CCSelectMindmap();
            ccSelectMindmap.SelectMindmap((sender as ListBox).SelectedIndex);
            updateMindmap();

            CCSelectComponent ccSelectComponent = Service.GetInstance.GetCCSelectComponent;
            ccSelectComponent.ResetSelection();
        }

        /// <summary>
        /// Deletes the current selected mindmap.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnDeleteMindmap_Click(object sender, EventArgs e)
        {
            int id = listExplorer.SelectedIndex;
            DialogResult result = MessageBox.Show("Are you sure you want to delete the mindmap '" + listExplorer.SelectedItem.ToString() + "'?", 
                                                  "Warning!", 
                                                  MessageBoxButtons.YesNo, 
                                                  MessageBoxIcon.Warning, 
                                                  MessageBoxDefaultButton.Button2);
            if (result == DialogResult.Yes)
            {
                CCDeleteMindmap ccDeleteMindmap = new CCDeleteMindmap();
                if (!ccDeleteMindmap.DeleteMindmap(id))
                {
                    MessageBox.Show("Something went wrong deleting the mindmap. Are you trying to delete the head mindmap or the last one left?", "Error!", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
                updateMindmapList();
                updateMindmap();
            }
        }

        /// <summary>
        /// Moves the current selected component.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnMoveComponent_Click(object sender, EventArgs e)
        {
            lastSelected = LastSelected.Move;
            this.MouseDown += Main_MouseDown;
        }

        /// <summary>
        /// Runs the Presentation Dialog.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void msiRunPresentation_Click(object sender, EventArgs e)
        {
            Presentation presentationDialog = new Presentation();
            presentationDialog.Show();
        }

        /// <summary>
        /// Shows the Help Dialog.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void msiHelp_Click(object sender, EventArgs e)
        {
            Help help = new Help();
            help.ShowDialog();
        }

        /// <summary>
        /// Starts a new project, creates a new File.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void msiNewProject_Click(object sender, EventArgs e)
        {
            CCCreateFile ccCreateFile = new CCCreateFile();
            ccCreateFile.CreateProject();
            updateMindmap();
            updateMindmapList();
        }

        /// <summary>
        /// Occurs when a user double clicks a selected control.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Main_DoubleClick(object sender, EventArgs e)
        {
            MouseEventArgs me = e as MouseEventArgs;

            CCAddBody ccAddBody = new CCAddBody();
            int id = ccAddBody.Alternate();

            if (id != -1)
            {
                listExplorer.SelectedIndex = id;
            }
        }

        /// <summary>
        /// Add an alternate function to a component.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnAddAlternate_Click(object sender, EventArgs e)
        {
            Alternate alternateForm = new Alternate();
            DialogResult result = alternateForm.ShowDialog();
            if (result == DialogResult.OK)
            {
                CCEditSelected ccEditSelected = new CCEditSelected();
                Action action = alternateForm.GetAction;

                switch (action)
                {
                    case Action.Mindmap:
                        ccEditSelected.AddAlternate("mindmap:" + alternateForm.Argument);
                        break;
                    case Action.File:
                        ccEditSelected.AddAlternate("file:" + alternateForm.Argument);
                        break;
                    case Action.Site:
                        if (alternateForm.Argument.ToLower().StartsWith("http:"))
                        {
                            ccEditSelected.AddAlternate(alternateForm.Argument);
                        }
                        else
                        {
                            ccEditSelected.AddAlternate("http:" + alternateForm.Argument);
                        }
                        break;
                }

                updateMindmap();
            }
        }

        /// <summary>
        /// Export a mindmap to an image. Needs more work, for it has not been implemented into the usecases yet.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void msiExportAsImage_Click(object sender, EventArgs e)
        {
            sfdMain.Filter = "JPeg Image|*.jpg|Bitmap Image|*.bmp|Gif Image|*.gif|PNG Image|*.png";
            sfdMain.ShowDialog();

            if (sfdMain.FileName != "")
            {
                System.IO.FileStream fs = (System.IO.FileStream)sfdMain.OpenFile();
                switch (sfdMain.FilterIndex)
                {
                    case 1:
                        this.screen.Save(fs,System.Drawing.Imaging.ImageFormat.Jpeg);
                        break;
                    case 2:
                        this.screen.Save(fs,System.Drawing.Imaging.ImageFormat.Bmp);
                        break;
                    case 3:
                        this.screen.Save(fs,System.Drawing.Imaging.ImageFormat.Gif);
                        break;
                    case 4:
                        this.screen.Save(fs,System.Drawing.Imaging.ImageFormat.Png);
                        break;                        
                }
                fs.Close();
            }
        }
    }
}
